/**
 * 
 */
package com.nextive.interview.activity;

import static com.nextive.interview.ApplicationManager.fetchService;
import static com.nextive.interview.activity.view.DefaultTextValuesHolder.fetchValueFor;
import static com.nextive.interview.service.WeightInfoService.DECIMAL_FORMAT;

import java.util.Calendar;
import java.util.List;

import android.app.Activity;
import android.app.AlertDialog;
import android.app.DatePickerDialog;
import android.app.DatePickerDialog.OnDateSetListener;
import android.app.Dialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.os.Bundle;
import android.provider.ContactsContract;
import android.text.Html;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.widget.Button;
import android.widget.CompoundButton;
import android.widget.CompoundButton.OnCheckedChangeListener;
import android.widget.DatePicker;
import android.widget.LinearLayout;
import android.widget.TextSwitcher;
import android.widget.ToggleButton;

import com.nextive.interview.R;
import com.nextive.interview.activity.SetupActivity.SettingsMode;
import com.nextive.interview.activity.view.DefaultTextSwitcherFactory;
import com.nextive.interview.dto.UserPreferences;
import com.nextive.interview.dto.WeightDateSingleLog;
import com.nextive.interview.service.UserInfoService;
import com.nextive.interview.service.WeightInfoService;
import com.nextive.interview.util.DateUtil;
import com.nextive.interview.util.PhoneContactsUtil;
import com.nextive.interview.util.ValidationUtil;

/**
 * Activity class to manage share function. It is in charge of sharing any weight 
 * history through email.
 * @author Cesar Roman
 *
 */
public class ShareWeightActivity extends Activity {

	/**
	 * Text switcher containing recipient email address.
	 */
	private TextSwitcher recipientDisplay;
	
	/**
	 * Text switcher containing history date to retrieve information since.
	 */
	private TextSwitcher historyDateDisplay;
	
	/**
	 * Button so to pick up a recipient.
	 */
	private Button pickShareRecipientButton;

	/**
	 * Button so to pick up a date.
	 */
	private Button pickDateButton;
	
	/**
	 * Layout for the date text.
	 */
	private LinearLayout dateLayout;
	
	/**
	 * Button so to share info.
	 */
	private Button shareButton;
	
	/**
	 * Cancel button, go back to previous state without saving.
	 */
	private Button cancelButton;
	
	/**
	 * Toggle button so to decide whether to select a specific date.
	 */
	private ToggleButton dateDeciderToggleButton;
	
	/**
	 * Date dialog to pick up a date.
	 */
	private DatePickerDialog dateDialog;

	/**
	 * Recipient dialog to pick up a recipient's email.
	 */
	private AlertDialog recipientDialog;

	/**
	 * Calendar containing date to share info since.
	 */
	private Calendar calendar;
	
	/**
	 * Recipient's email.
	 */
	private String recipientEmail;
		
	/**
	 * Date dialog id descriptor.
	 */
	private static final int DATE_DIALOG_ID = 0;
	
	/**
	 * Recipient dialog id descriptor.
	 */
	private static final int RECIPIENT_DIALOG_ID = 1;
	
	/**
	 * Activity create state.
	 */
	private static final int ACTIVITY_CREATE = 0;
	
	/**
	 * Service to obtain user preferences.
	 */
	private UserInfoService userInfoService;
	
	/**
	 * Service to obtain weight entries.
	 */
	private WeightInfoService weightInfoService;
	
	/**
	 * DTO object containing user preferences info.
	 */
	private UserPreferences userPreferences;
	
	/**
	 * Main method for this activity. It is in charge of configuring all layouts of the screen.
	 * @param savedInstanceState
	 */
	protected void onCreate(Bundle savedInstanceState) {
		
		super.onCreate(savedInstanceState);
		userInfoService = fetchService(UserInfoService.class);
		weightInfoService = fetchService(WeightInfoService.class);
		setContentView(R.layout.weight_share);
		
		bindInputs();
		
		handleLastNonConfigurationInstance();
		configureRecipientDisplay();
		configureDateDisplay();
		configureRecipientButton();
		configurePickDateButton();
		configureShareButton();
		configureCancelButton();
		updateDateDisplay();
		updateRecipientDisplay(recipientEmail);
		
	}

	/**
	 * It loads user preferences to be used later on.
	 */
	@Override
	protected void onResume() {

		super.onResume();
		userPreferences = userInfoService.fetchUserInfo();
		
	}

	/**
	 * It creates the options menu. This is done via inflating menu.
	 * @param menu
	 */
	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		
		MenuInflater inflater = getMenuInflater();
		inflater.inflate(R.menu.settings_options_menu, menu);
		return true;
		
	}
	
	/**
	 * It forwards flow to setup activity.
	 */
	@Override
	public boolean onOptionsItemSelected(MenuItem item) {
		
		switch (item.getItemId()) {
		case R.id.settings_menu:
			forwardToSettingsActivity();
		}
		
		return super.onOptionsItemSelected(item);
	}

	/**
	 * It is in charge of creating dialogs. It can create either a change 
	 * date dialog as well as a change recipient dialog.
	 * 
	 */
	@Override
	protected Dialog onCreateDialog(int id) {
		
		switch (id) {
		case DATE_DIALOG_ID:
			return dateDialog;
		case RECIPIENT_DIALOG_ID:
			return recipientDialog;
		}
		
		return null;
		
	}

	/**
	 * It takes care of handling the result when creating a new contact.
	 */
    @Override
	protected void onActivityResult(int requestCode, int resultCode, Intent data) {
		
		super.onActivityResult(requestCode, resultCode, data);
		if (RESULT_OK == resultCode && ACTIVITY_CREATE == requestCode) {
			
			String email = PhoneContactsUtil.getContactDetails(data.getData()).getEmail();
			if (ValidationUtil.isValidEmailInput(email)) {

				updateRecipientDisplay(email);
				displayDefaultRecipientDialog(email);
				recipientEmail = email;

			} else {
				
				ValidationUtil.rejectValidationForView(null, R.string.contact_email_error);
				
			}
			
		}
		
	}

    /**
     * It saves partial information so to be populated when activity comes to foreground again.
     * @return a WeightDateSingleLog
     */
    @Override
	public Object onRetainNonConfigurationInstance() {
		
    	if (dateDeciderToggleButton.isChecked())
    		return new ShareInformationHolder(recipientEmail, calendar);
    	
    	return new ShareInformationHolder(recipientEmail, null);
	}

	/**
	 * It is in charge of binding all inputs of the view.
	 */
	private void bindInputs() {
		
		recipientDisplay = (TextSwitcher) findViewById(R.id.recipient_share_id);
		historyDateDisplay = (TextSwitcher) findViewById(R.id.date_history_share_id);
		pickShareRecipientButton = (Button) findViewById(R.id.pickUpShareRecipient);
		pickDateButton = (Button) findViewById(R.id.date_history_button_id);
		dateLayout = (LinearLayout) findViewById(R.id.share_date_layout_id);
		dateDeciderToggleButton = (ToggleButton) findViewById(R.id.date_history_toggle_button_id);
		shareButton = (Button) findViewById(R.id.confirm_share);
		cancelButton = (Button) findViewById(R.id.cancel_share);
		
	}

    /**
     * It configures recipient display. This is a text switcher which will 
     * show selected recipient email as text.
     */
    private void configureRecipientDisplay() {
    	
    	recipientDisplay.setFactory(new DefaultTextSwitcherFactory(R.style.InsideRowSmallTextStyle));
    	Animation in = AnimationUtils.loadAnimation(this,
                android.R.anim.slide_in_left);
        Animation out = AnimationUtils.loadAnimation(this,
                android.R.anim.slide_out_right);
        recipientDisplay.setInAnimation(in);
        recipientDisplay.setOutAnimation(out);
        
		AlertDialog.Builder builder = new AlertDialog.Builder(this);
		builder.setTitle(R.string.select_recipient_dialog_title);
		builder.setItems(R.array.dialog_share_recipient_options, 
			new DialogInterface.OnClickListener() {
			
			@Override
			public void onClick(DialogInterface dialog, int which) {
			
				switch (which) {
				case 0:
					// Myself contact
					handleMyselfRecipient();
					break;
				case 1:
					// Choose default recipient
					handleDefaultRecipient();
					break;
				case 2:
					// Create a new contact
					handleNewContact();
					break;
				}
				
			}
		});
		
		recipientDialog = builder.create();

    }

    /**
     * It configures date text switcher display. It sets the factory and animations.
     */
	private void configureDateDisplay() {
		
		if (calendar == null)
			calendar = Calendar.getInstance();
		calendar.set(Calendar.HOUR_OF_DAY, 0);
    	calendar.set(Calendar.MINUTE, 0);
    	calendar.set(Calendar.SECOND, 0);
		historyDateDisplay.setFactory(new DefaultTextSwitcherFactory(R.style.InsideRowSmallTextStyle));
    	Animation in = AnimationUtils.loadAnimation(this,
                android.R.anim.slide_in_left);
        Animation out = AnimationUtils.loadAnimation(this,
                android.R.anim.slide_out_right);
        historyDateDisplay.setInAnimation(in);
        historyDateDisplay.setOutAnimation(out);
        
        dateDialog = new DatePickerDialog(this, new OnDateSetListener() {
			
			@Override
			public void onDateSet(DatePicker view, int yearIn, int monthOfYear,
					int dayOfMonth) {

				calendar.set(Calendar.YEAR, yearIn);
				calendar.set(Calendar.MONTH, monthOfYear);
				calendar.set(Calendar.DAY_OF_MONTH, dayOfMonth);
				updateDateDisplay();
				
			}
		}, calendar.get(Calendar.YEAR), calendar.get(Calendar.MONTH), calendar.get(Calendar.DAY_OF_MONTH));
        
        dateDeciderToggleButton.setOnCheckedChangeListener(new OnCheckedChangeListener() {
			
			@Override
			public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {

				dateLayout.setVisibility(isChecked ? View.VISIBLE : View.GONE);
				
			}
		});
        
	}

    /**
     * It configures recipient button. It sets corresponding click listener.
     */
    private void configureRecipientButton() {

		pickShareRecipientButton.setOnClickListener(new OnClickListener() {
			
			@Override
			public void onClick(View v) {
			
				showDialog(RECIPIENT_DIALOG_ID);
				
			}
		});

	}

	/**
	 * It configures pick date button. Whenever this button is clicked, a 
	 * date picker dialog will be shown.
	 */
	private void configurePickDateButton() {

		pickDateButton.setOnClickListener(new OnClickListener() {
			
			@Override
			public void onClick(View v) {
			
				showDialog(DATE_DIALOG_ID);
				
			}
		});

	}

	/**
	 * It configures share button. Whenever this button is clicked, information will be shared.
	 */
	private void configureShareButton() {

		shareButton.setOnClickListener(new OnClickListener() {
			
			@Override
			public void onClick(View v) {
			
				shareInfo();
				
			}
		});

	}
	
	/**
	 * It configures cancel button. Whenever this button is clicked, activity 
	 * is considered as finished without any saving.
	 */
	private void configureCancelButton() {

		cancelButton.setOnClickListener(new OnClickListener() {
			
			@Override
			public void onClick(View v) {
			
				setResult(RESULT_OK);
				finish();
				
			}
		});

	}

	/**
	 * It is in charge of sharing information. It first fetches weight 
	 * information and then forward it to send email activity.
	 * @return true if information has been shared successfully
	 */
	private boolean shareInfo() {
		
		List<WeightDateSingleLog> weightLogsToShare;
		if (dateDeciderToggleButton.isChecked()) {
			
			// date has been selected
			weightLogsToShare = weightInfoService.fetchWeightInfoSince(calendar);
			
		} else {
			
			// fetch all
			weightLogsToShare = weightInfoService.fetchAllWeightInfo();
			
		}
		if (performValidation(recipientEmail, weightLogsToShare)) {
			
			forwardToSendEmailActivity(generateHTML(weightLogsToShare));
			return true;
			
		}
		
		return false;
		
	}
	
	/**
	 * It performs validation for recipient email and weight entries to be shared.
	 * @param email the recipient email
	 * @param entries the entries to be shared
	 * @return true if valid
	 */
	private boolean performValidation(String email, List<WeightDateSingleLog> entries) {
	
		if (!ValidationUtil.isValidEmailInput(email)) {
			
			ValidationUtil.rejectValidationForView(recipientDisplay, R.string.recipient_email_error);
			return false;
			
		}
		if (entries == null || entries.isEmpty()) {
			
			ValidationUtil.rejectValidationForView(null, R.string.nothing_to_share);
			return false;
			
		}
		
		return true;

	}
	
	/**
	 * It generates html to be sent based on the given weight entries.
	 * @param entries the weight entries to share
	 * @return generated html
	 */
	private String generateHTML(List<WeightDateSingleLog> entries) {
		
		String dateHeader = fetchValueFor(R.string.share_date_header).toString();
		String weightHeader = fetchValueFor(R.string.share_weight_header).toString();
		String metricDisplay = UserInfoService.Metric.KG.equals(userPreferences.getMetricOption()) ? 
				fetchValueFor(R.string.kg_metric).toString() : fetchValueFor(R.string.lb_metric).toString();
		
		StringBuilder message = new StringBuilder();
		message.append("<html><body><pre>");
		message.append("<b><big><i>" + dateHeader + "</b></big></i>");
		message.append("\t\t\t\t\t\t");
		message.append("<b><big><i>" + weightHeader + "</b></big></i>");
		message.append("<br/>");
		for (WeightDateSingleLog currentEntry : entries) {
		
			message.append(DateUtil.generateVisualDate(currentEntry.getCalendar(), false) + "&nbsp;" + 
					DateUtil.generateVisualTime(currentEntry.getCalendar()));
			message.append("\t\t\t");
			message.append(DECIMAL_FORMAT.format(currentEntry.getWeight()) + "&nbsp;" + metricDisplay);
			message.append("<br/>");
			
		}
		
		message.append("</pre></body></html>");
		
		return message.toString();
		
	}
	
	/**
	 * It forwards the flow to activity in charge of sending emails.
	 * @param html the html to send
	 */
	private void forwardToSendEmailActivity(String html) {
		
		Intent intent = new Intent(Intent.ACTION_SEND);
		intent.setType("text/html");
		intent.putExtra(Intent.EXTRA_TEXT, Html.fromHtml(html));
		intent.putExtra(Intent.EXTRA_EMAIL, new String[] { recipientEmail });
		intent.putExtra(Intent.EXTRA_SUBJECT, getString(R.string.email_subject_share));
		
		startActivity(Intent.createChooser(intent, getString(R.string.choose_email_app_share)));
		
	}
	
	/**
	 * It forwards flow to settings activity. It puts into the intent 
	 * <code>CHANGE_SETTIGNS</code> flag so to be able to update user settings.
	 */
	private void forwardToSettingsActivity() {
		
		Intent intent = new Intent(this, SetupActivity.class);
		intent.putExtra(SettingsMode.CHANGE_SETTINGS.name(), true);
		
		startActivity(intent);
		
	}

	/**
	 * It updates date display text and dialog. It takes inputs from year, month and day to make 
	 * a single text and update its dialog.
	 */
    private void updateDateDisplay() {

		historyDateDisplay.setText(DateUtil.generateVisualDate(calendar));
		dateDialog.updateDate(
				calendar.get(Calendar.YEAR), 
				calendar.get(Calendar.MONTH), 
				calendar.get(Calendar.DAY_OF_MONTH));

	}

    /**
     * It updates recipient display. It sets text switcher text given the email.
     * @param emailDisplay email to be displayed
     */
    private void updateRecipientDisplay(String emailDisplay) {
    
    	if (emailDisplay == null || "".equals(emailDisplay))
    		emailDisplay = fetchValueFor(R.string.choose_recipient).toString();
    	
    	recipientDisplay.setText(emailDisplay);
    	
    }

    /**
     * It displays a pop up dialog so to be able to set new default recipient email.
     * @param email new default recipient email
     */
    private void displayDefaultRecipientDialog(final String email) {
    	
		AlertDialog.Builder builder = new AlertDialog.Builder(this);
		builder.setMessage(String.format(fetchValueFor(R.string.set_default_recipient_share).toString(), email));
		builder.setPositiveButton(R.string.yes, new DialogInterface.OnClickListener() {
			@Override
			public void onClick(DialogInterface dialog, int which) {
				
				userPreferences.setRecipientEmail(email);
				userInfoService.saveOrUpdateUserInfo(userPreferences);
				
			}
		});
		builder.setNegativeButton(R.string.no, new DialogInterface.OnClickListener() {
			@Override
			public void onClick(DialogInterface dialog, int which) {
				
				// Do nothing
			}
		});
		builder.create().show();
    	
    }
    
	/**
	 * It handles the case when we rotate screen, updating email and calendar variables.
	 */
	private void handleLastNonConfigurationInstance() {
		
		ShareInformationHolder infoHolder = (ShareInformationHolder) getLastNonConfigurationInstance();
		recipientEmail =  infoHolder == null ? null : infoHolder.getRecipientEmail();
		calendar = infoHolder == null || infoHolder.getCalendar() == null ? Calendar.getInstance() : infoHolder.getCalendar();
		
	}

	/**
	 * When Myself has been chosen it updates email recipient with user's email.
	 */
    private void handleMyselfRecipient() {
	
    	UserPreferences preferences = userInfoService.fetchUserInfo();
		updateRecipientDisplay(preferences.getEmail());
		recipientEmail = preferences.getEmail();
		
	}

	/**
	 * When New contact has been chosen it starts new contact activity from Contacts app.
	 */
    private void handleNewContact() {
		
		Intent intent = new Intent(Intent.ACTION_INSERT, ContactsContract.Contacts.CONTENT_URI);
		startActivityForResult(intent, ACTIVITY_CREATE);
		
	}

    /**
	 * When Myself has been chosen it updates email recipient with default recipient user's email.
	 */
	private void handleDefaultRecipient() {
		
    	UserPreferences preferences = userInfoService.fetchUserInfo();
		updateRecipientDisplay(preferences.getRecipientEmail());
		recipientEmail = preferences.getRecipientEmail();
		
	}
	
	private class ShareInformationHolder {
		
		private String recipientEmail;
		
		private Calendar calendar;
		
		public ShareInformationHolder(String email, Calendar calendarIn) {
			
			recipientEmail = email;
			calendar = calendarIn;
			
		}

		public String getRecipientEmail() {
			return recipientEmail;
		}

		public Calendar getCalendar() {
			return calendar;
		}
		
	}

}